package sojo.com.inverter.service.Impl.core;


import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import sojo.com.inverter.entity.DeviceCode;
import sojo.com.inverter.entity.InverterVo;
import sojo.com.inverter.entity.VoltageCurrent;
import sojo.com.inverter.modbus.ModbusClient;
import sojo.com.inverter.service.Device;
import sojo.com.inverter.service.DeviceCodeService;
import sojo.com.inverter.service.DeviceProtocolService;
import sojo.com.inverter.utils.ToolsUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author cheng_hu
 * @description:
 * @date 2023-02-22 15:13:45
 */
@Slf4j
@Service("huaweiInverter")
public class HuaweiInverterServiceImpl implements DeviceProtocolService {

    //协议id
    private final String protocolId = "011";

    private final int offset = 30000;
    @Autowired
    private DeviceCodeService deviceCodeService;

    @Override
    public void analysisData(ModbusClient modbusClient, Device device) {

        int slaveId = 1;
        List<DeviceCode> deviceCodeList = deviceCodeService.lambdaQuery().eq(DeviceCode::getProtocolId, protocolId).list();
        if (CollUtil.isEmpty(deviceCodeList)) {
            return;
        }

        byte[] results1 = modbusClient.modbusTCP03(slaveId, offset, 15);
        if (results1 == null) {
            log.error("逆变器 连接失败 ");
            return;
        }

        for (DeviceCode deviceCode : deviceCodeList) {

            InverterVo inverterVo = new InverterVo();
            inverterVo.setDeviceId(Integer.parseInt(deviceCode.getDeviceId()));
            inverterVo.setDeviceName(deviceCode.deviceName);
            // 机型名称 30000
//            short[] results1 = modbusClient.readHoldingRegister(slaveId, offset, 15);
//            if (results1 == null) {
//                continue;
//            }

            // SN   30015  设备编号
            byte[] sn = modbusClient.modbusTCP03(slaveId, 30015, 10);
            if (sn == null) {
                continue;
            }
            String snNo = ToolsUtil.asciiToString2(sn, 0, sn.length);
            inverterVo.setSn(snNo);
            // PN   30025
            byte[] pn = modbusClient.modbusTCP03(slaveId, 30025, 10);
            if (pn == null) {
                continue;
            }
            String pnStr = ToolsUtil.asciiToString2(pn, 0, pn.length);
            inverterVo.setPn(pnStr);
            log.info("SN:{} PN:{}", snNo, pnStr);

            byte[] dvId = modbusClient.modbusTCP03(slaveId, 30070, 3);
            if (dvId == null) {
                continue;
            }
            respond_30070(inverterVo, dvId);

            byte[] Pn_Qmax = modbusClient.modbusTCP03(slaveId, 30073, 10);
            if (Pn_Qmax == null) {
                continue;
            }
            respond_30073(inverterVo, Pn_Qmax);

            // 状态1  开始 32000
            //Bit0：待机Bit1：并网 Bit2：正常并网 Bit3：限电降额并网/ Bit4：自降额并网 Bit5：正常停运 Bit6：故障停运 Bit7：限电停运 Bit8：关机 Bit9：点检
            byte[] state_1 = modbusClient.modbusTCP03(slaveId, 32000, 1);
            if (state_1 == null) {
                continue;
            }
            int st = ToolsUtil.bytesToIntHigh(state_1, 0, 2);
            inverterVo.setRunMode(st + "");

            byte[] state_2_3 = modbusClient.modbusTCP03(slaveId, 32002, 3);
            if (state_2_3 == null) {
                continue;
            }
            respond_32002(inverterVo, state_2_3);

            // 1  告警1 32008
            byte[] warn = modbusClient.modbusTCP03(slaveId, 32008, 5);
            if (warn == null) {
                continue;
            }
            respond_32008(inverterVo, warn);

            // TODO: 2023/2/24 共24对
            // 2  PV1电压  32016  PV1电流  32017
            byte[] pv1_24 = modbusClient.modbusTCP03(slaveId, 32016, 48);
            if (pv1_24 == null) {
                continue;
            }
            ArrayList<VoltageCurrent> arrayList = extracted(pv1_24, pv1_24.length / 24);
            List<Double> voltage = arrayList.stream().map(VoltageCurrent::getVoltage).collect(Collectors.toList());
            List<Double> current = arrayList.stream().map(VoltageCurrent::getCurrent).collect(Collectors.toList());
            String v = voltage.stream().map(String::valueOf).collect(Collectors.joining(","));
            String c = current.stream().map(String::valueOf).collect(Collectors.joining(","));
            // PV25电压 32344   PV28电流 32351 1
            byte[] pv_25 = modbusClient.modbusTCP03(slaveId, 32344, 8);
            if (pv_25 == null) {
                continue;
            }
            ArrayList<VoltageCurrent> arrayList1 = extracted(pv_25, pv_25.length / 4);
            List<Double> voltage1 = arrayList1.stream().map(VoltageCurrent::getVoltage).collect(Collectors.toList());
            List<Double> current1 = arrayList1.stream().map(VoltageCurrent::getCurrent).collect(Collectors.toList());
            String v1 = voltage1.stream().map(String::valueOf).collect(Collectors.joining(","));
            String c1 = current1.stream().map(String::valueOf).collect(Collectors.joining(","));

            inverterVo.setVoltageArray(v + "," + v1);
            inverterVo.setCurrentArray(c + "," + c1);
            log.info("PV1-28电压:{}", v + "," + v1);
            log.info("PV1-28电流:{}", c + "," + c1);

            byte[] power_time = modbusClient.modbusTCP03(slaveId, 32064, 31);
            if (power_time == null) {
                continue;
            }
            respond_32064(inverterVo, power_time);

            // 累计发电量  32106  2   0.01
            byte[] total = modbusClient.modbusTCP03(slaveId, 32106, 2);
            if (total == null) {
                continue;
            }
            double totalElectric = ToolsUtil.bytesToIntHigh(total, 0, 4) * 0.01;
            inverterVo.setTotalElectric(totalElectric);
            // 当日发电量  32114  2   0.01
            byte[] day = modbusClient.modbusTCP03(slaveId, 32114, 2);
            if (day == null) {
                continue;
            }
            double inverterDayElec = ToolsUtil.bytesToIntHigh(day, 0, 4) * 0.01;
            inverterVo.setInverterDayElec(inverterDayElec);
            log.info("累计发电量:{} 当日发电量:{}", total, day);

            //发送kafka，并存时序库
            device.analysisData(inverterVo);

        }


    }

    /**
     * //1 机型ID  30070  // 组串个数 30071 // MPPT个数  30072   U16*
     */
    private void respond_30070(InverterVo inverterVo, byte[] bytes) {
        int start = 0;
        int dv = ToolsUtil.bytesToIntHigh(bytes, start, 2);
        inverterVo.setDeviceId(dv);
        int num = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2);
        inverterVo.setGroupNum(num);
        int mpp = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2);
        inverterVo.setMpptId(mpp);
        log.info("机型ID:{} 组串个数:{} MPPT个数:{}", dv, num, mpp);
    }

    /**
     * 2  额定功率（Pn） 30073   // 最大有功 开始 30075   // 最大视在 30077
     * 最大无功 （Qmax,向电网馈入）开始 30079  I32   // 最大无功（Qmax,从电网吸收） 30081      I32
     */
    private void respond_30073(InverterVo inverterVo, byte[] bytes) {
        int start = 0;
        double ratedPower = ToolsUtil.bytesToIntHigh(bytes, start, 4) * 0.001;
        inverterVo.setRatedPower(ratedPower);
        double activePowerMax = ToolsUtil.bytesToIntHigh(bytes, start += 4, 4) * 0.001;
        inverterVo.setActivePowerMax(activePowerMax);
        double apparentPowerMax = ToolsUtil.bytesToIntHigh(bytes, start += 4, 4) * 0.001;
        inverterVo.setApparentPowerMax(apparentPowerMax);
        //I32
        double reactiveFeedPowerMax = ToolsUtil.bytesToUnIntHigh(bytes, start += 4, 4) * 0.001;
        inverterVo.setReactiveFeedPowerMax(reactiveFeedPowerMax);
        double reactiveAbsorbPowerMax = ToolsUtil.bytesToUnIntHigh(bytes, start += 4, 4) * 0.001;
        inverterVo.setReactiveAbsorbPowerMax(reactiveAbsorbPowerMax);
        log.info("额定功率（Pn）:{} 最大有功:{}  最大视在:{} 最大无功 （Qmax,向电网馈入）:{} 最大无功（Qmax,从电网吸收）:{}",
                ratedPower, activePowerMax, apparentPowerMax, reactiveFeedPowerMax, reactiveAbsorbPowerMax);
    }

    /**
     * // 状态2 32002  1  //Bit0：闭锁状态（0：闭锁，1：非闭锁） Bit1：PV连接状态(0：未连接，1：连接) Bit2：DSP数据采集状态(0：无，1：有)
     * // 状态3 32003  2  //Bit0：离网（0：非离网，1：离网） Bit1：离网使能开关（0：弹起，1：按下）*
     */
    private void respond_32002(InverterVo inverterVo, byte[] bytes) {
        int start = 0;
        int st2 = ToolsUtil.bytesToIntHigh(bytes, start, 1);
        int st2_2 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        inverterVo.setState_2(st2 + "," + st2_2);
        int st3_1 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        int st3_2 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        int st3_3 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        int st3_4 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        inverterVo.setState_3(st3_1 + "," + st3_2 + "," + st3_3 + "," + st3_4);
        log.info("状态2:{},{} 状态3:{},{},{},{}", st2, st2_2, st3_1, st3_2, st3_3, st3_4);
    }

    /**
     * 1  告警1 32008*
     *
     * @param bytes
     */
    private void respond_32008(InverterVo inverterVo, byte[] bytes) {
        int start = 0;
        int wa1 = ToolsUtil.bytesToIntHigh(bytes, start, 1);
        int wa1_1 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        inverterVo.setWarn_1(wa1 + "," + wa1_1);
        int wa2 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        int wa2_1 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        inverterVo.setWarn_2(wa2 + "," + wa2_1);
        int wa3 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        int wa3_1 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        inverterVo.setWarn_3(wa3 + "," + wa3_1);
        int wa4 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        int wa4_1 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        inverterVo.setWarn_4(wa4 + "," + wa4_1);
        int wa5 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        int wa5_1 = ToolsUtil.bytesToIntHigh(bytes, start += 1, 1);
        inverterVo.setWarn_5(wa5 + "," + wa5_1);
        log.info("告警1 :{},{} 告警2:{},{}  告警3:{},{}  告警4:{},{}  告警5:{},{}", wa1, wa1_1, wa2, wa2_1, wa3, wa3_1, wa4, wa4_1, wa5, wa5_1);
    }

    /**
     * 2 输入功率  32064
     * 1  电网AB线电压 32066 //电网BC线电压 32067 //电网CA线电压 32068 //电网A相电压 32069 //电网B相电压 32070 //电网C相电压 32071
     * 2  电网A相电流  32072  2  //84 电网B相电流 32074 2 //85 电网C相电流 32076 2 //86 当天峰值有功功率 32078 2  //   有功功率 32080 2  //88 无功功率 32082 2
     * 1  功率因数  32084  1  //90 电网频率 //91 效率 //92 内部温度 //93 绝缘阻抗值 //94 设备状态 32089 1 // 95 故障码 32090 1
     * 2  开机时间 32091 2 // 关机时间 32093 2
     */
    private void respond_32064(InverterVo inverterVo, byte[] bytes) {
        int start = 0;
        double arrayPower = ToolsUtil.bytesToUnIntHigh(bytes, start, 4) * 0.001;
        inverterVo.setArrayPower(arrayPower);
        double voltageAB = ToolsUtil.bytesToIntHigh(bytes, start += 4, 2) * 0.1;
        inverterVo.setVoltageAB(voltageAB);
        double vo_bc = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2) * 0.1;
        inverterVo.setVoltageBC(vo_bc);
        double vo_ca = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2) * 0.1;
        inverterVo.setVoltageCA(vo_ca);
        double vo_a = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2) * 0.1;
        inverterVo.setVoltageA(vo_a);
        double vo_b = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2) * 0.1;
        inverterVo.setVoltageB(vo_b);
        double vo_c = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2) * 0.1;
        inverterVo.setVoltageC(vo_c);

        double cu_a = ToolsUtil.bytesToUnIntHigh(bytes, start += 2, 4) * 0.001;
        inverterVo.setCurrentA(cu_a);
        double cu_b = ToolsUtil.bytesToUnIntHigh(bytes, start += 4, 4) * 0.001;
        inverterVo.setCurrentB(cu_b);
        double cu_c = ToolsUtil.bytesToUnIntHigh(bytes, start += 4, 4) * 0.001;
        inverterVo.setCurrentC(cu_c);
        log.info("输入功率:{} 电网AB线电压:{} 电网BC线电压:{} 电网CA线电压:{} 电网A相电压:{} 电网B相电压:{} 电网C相电压:{} 电网A相电流:{} 电网B相电流:{} 电网C相电流:{} ",
                arrayPower, voltageAB, vo_bc, vo_ca, vo_a, vo_b, vo_c, cu_a, cu_b, cu_c);

        double theDayActivePower = ToolsUtil.bytesToUnIntHigh(bytes, start += 4, 4) * 0.001;
        inverterVo.setTheDayActivePower(theDayActivePower);
        double activePower = ToolsUtil.bytesToUnIntHigh(bytes, start += 4, 4) * 0.001;
        inverterVo.setActivePower(activePower);
        double reactivePower = ToolsUtil.bytesToUnIntHigh(bytes, start += 4, 4) * 0.001;
        inverterVo.setReactivePower(reactivePower);

        double powerFactor = ToolsUtil.bytesToUnIntHigh(bytes, start += 4, 2) * 0.001;
        inverterVo.setPowerFactor(powerFactor);

        double frequency = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2) * 0.01;
        inverterVo.setFrequency(frequency);
        double inverterEfficiency = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2) * 0.01;
        inverterVo.setInverterEfficiency(inverterEfficiency);
        log.info("当天峰值有功功率:{} 有功功率:{} 无功功率:{} 功率因数:{} 电网频率:{} 效率:{}",
                theDayActivePower, activePower, reactivePower, powerFactor, frequency, inverterEfficiency);

        double inverterTem = ToolsUtil.bytesToUnIntHigh(bytes, start += 2, 2) * 0.1;
        inverterVo.setInverterTem(inverterTem);
        double insulation = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2) * 0.001;
        inverterVo.setInsulation(insulation);

        // TODO: 2023/2/24 InverterStateEnum
        int inverterState = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2);
        inverterVo.setInverterState(inverterState);
        //故障码
        int warnCode = ToolsUtil.bytesToIntHigh(bytes, start += 2, 2);
        inverterVo.setWarnCode(warnCode);

        //todo 时间转换   DateUtil.getDate3(byteArrayToHexString(data, start += 8, 7))
        int openTime = ToolsUtil.bytesToIntHigh(bytes, start += 2, 4);
        inverterVo.setOpenTime(openTime);
        int closeTime = ToolsUtil.bytesToIntHigh(bytes, start += 4, 4);
        inverterVo.setCloseTime(closeTime);
        log.info("内部温度:{} 绝缘阻抗值:{} 设备状态:{} 故障码:{}  开机时间:{} 关机时间:{}",
                inverterTem, insulation, inverterState, warnCode, openTime, closeTime);

    }

    /**
     * //处理电压电流 2  PV1电压  32016  PV1电流  32017*
     */
    private ArrayList<VoltageCurrent> extracted(byte[] bytes, int len) {

        ArrayList<VoltageCurrent> arrayList = new ArrayList<>();
        int start = 0;
        for (int i = 0; i < len; i++) {
            VoltageCurrent voltageCurrent = new VoltageCurrent();
            double vo = ToolsUtil.bytesToUnIntHigh(bytes, start, 2) * 0.1;
            double cu = ToolsUtil.bytesToUnIntHigh(bytes, start += 2, 2) * 0.01;
            start += 2;
            voltageCurrent.setVoltage(vo);
            voltageCurrent.setCurrent(cu);
            arrayList.add(voltageCurrent);
        }
        return arrayList;
    }
}
